#include <QDebug>
#include <malloc.h>

#include "include/rm_schedule.h"
#include "include/simul.h"
#include "include/task.h"
#include "include/core.h"

//任务就绪
void taskNew(Task *task, Core *core)
{
    sched_EnqueueLocal(task, core);
}

//任务主动退出，返回被动退出任务的信息
Task* taskExit(Task *task, Core *core)
{
    sched_DequeueLocal(task, core);
    //更新周期任务已经执行的时间以及下一次到达时间
    task->execute_time = 0;
    task->arrival_time += task->task_period;
    task->ready_time = (task->arrival_time + task->task_jitter);
    task->isRestart = false; //便于在下一周期重新绘制释放箭头
    //更新处理器相关信息
    core->scheduled_prio = PrioMin;
    core->task_scheduled = -1;
    core->task_sched_type = -1;

    return nullptr;
}


Task* taskStop(Task *task, Core *core)
{
    qDebug() << "Task " << task->task_id << "(" << " exit." << endl;

    sched_DequeueLocal(task, core);

    //更新周期任务已经执行的时间以及下一次到达时间
    task->execute_time = 0;
    task->arrival_time += task->task_period;
    task->ready_time = (task->arrival_time + task->task_jitter);
    task->isRestart = false; //便于在下一周期重新绘制释放箭头

    //更新处理器相关信息
    core->scheduled_prio = PrioMin;
    core->task_scheduled = -1;
    core->task_sched_type = -1;

    return nullptr;
}

void show_readyqueue( Core *target_core)
{   qDebug()<<"time:"<<Time<<"核"<<target_core->core_id;
    for(ready_queue_node *temp=target_core->ready_queue->next;temp!=target_core->ready_queue;temp=temp->next)
        qDebug()<<"  "<<temp->task->task_id;
}

void show_suspendqueue(ready_queue_node *queue)
{   qDebug()<<"time:"<<Time<<"挂起队列";
    for(ready_queue_node *temp=queue->next;temp!=queue;temp=temp->next)
        qDebug()<<"  "<<temp->task->task_id;
}

void show_waitqueue()
{   qDebug()<<"time:"<<Time<<"wait queue";
    for(ready_queue_node *temp=wait_for_join->next;temp!=wait_for_join;temp=temp->next)
        qDebug()<<"  "<<temp->task->task_id;
}

/* ------------------------RM(Rate-Monotonic)------------------------------ */

void sched_suspendQueue(Task *task, Core *target_core)
{
    ready_queue_node *New = new ready_queue_node;
    New->task = task;
    ready_queue_node *pos;
    ready_queue_node *head = target_core->suspend_queue;
    for(pos = head->next; pos != head; pos = pos->next){
        if(pos->task->task_priority >= task->task_priority){
            add_task_list(New, pos->pre, pos);
            return;
        }
    }
    add_task_list_tail(New, head);
}

void sched_suspendDequeue(Task *task, Core *target_core)
{
    ready_queue_node *pos;
    ready_queue_node *head = target_core->suspend_queue;

    for(pos = head->next; pos != head; pos = pos->next){
        if(pos->task == task){
            del_task_list(pos->pre, pos->next);
            delete pos;
            return;
        }
    }
}
/*加入目标异地核的就绪队列*/
void sched_queueTrans(Task *task,ready_queue_node *newqueue,ready_queue_node *lastqueue)
{
    ready_queue_node *New = new ready_queue_node;
    New->task = task;
    ready_queue_node *pos;
    ready_queue_node *head = newqueue;
    bool add=false;
    for(pos = head->next; pos != head; pos = pos->next){
        if(pos->task->task_priority >= task->task_priority){
            add_task_list(New, pos->pre, pos);
            add=true;
        }
    }

    if(!add)
    add_task_list_tail(New, head);
    qDebug()<<"入队成功";

    ready_queue_node *pos2;
    ready_queue_node *head2 = lastqueue;

    for(pos2 = head2->next; pos2 != head2; pos2 = pos2->next){
        if(pos2->task == task){
            del_task_list(pos2->pre, pos2->next);
            delete pos2;
            qDebug()<<"出队成功";
            return;
        }
        return;
    }


}




/*加入目标本地核的就绪队列*/
void sched_EnqueueLocal(Task *task, Core *target_core)
{
    //给ready_queue_node 分配空间
    ready_queue_node *New = new ready_queue_node;
    //添加任务
    New->task = task;
    ready_queue_node *pos;
    ready_queue_node *head = target_core->ready_queue;
    for(pos = head->next; pos != head; pos = pos->next){
        if(pos->task->task_priority >= task->task_priority){
            add_task_list(New, pos->pre, pos);
            return;
        }
    }
    add_task_list_tail(New, head);
}

void sched_DequeueLocal(Task *task, Core *target_core)
{
    ready_queue_node *pos;
    ready_queue_node *head = target_core->ready_queue;

    for(pos = head->next; pos != head; pos = pos->next){
        if(pos->task == task){
            del_task_list(pos->pre, pos->next);
            delete pos;
            return;
        }
    }
}

/**
 * @brief 根据id得到core实例
 * @param core_id
 * @return
 */
Core *sched_GetCore(int core_id)
{
    for(int i = 0; i < M; ++i){
        if(cores[i].core_id == core_id)
            return &cores[i];
    }
    qDebug()<<"Error: GetLocalDom"<<endl;

    return nullptr;
}
/**
 * @brief 根据任务得到coredomain
 * @param task
 * @return
 */
Core *sched_GetTaskDom(Task *task)
{
    int core_id = task->on_core;
    for(int i = 0; i < M; ++i){
        if(cores[i].core_id == core_id)
            return &cores[i];
    }
    qDebug()<<"Error: GetTaskDom"<<endl;

    return nullptr;
}
/**
 * @brief 将任务设置到core里面
 * @param task
 * @param core
 */
void sched_SetLocalSchedTask(Task *task, Core *core)
{
    if(task == nullptr){
        core->task_scheduled = -1;
        core->scheduled_prio = PrioMin;
        core->task_sched_type =  -1;
    }
    else{
        core->task_scheduled = task->task_id;
        core->scheduled_prio = task->task_priority;
        core->task_sched_type = task->task_type;
    }
}

void sched_PrioTake(Core *core)
{
    Task *hp_task, *scheduled;
    //拿到头节点
    ready_queue_node *head = core->ready_queue;
    if(head->next != head){
        hp_task = head->next->task;
        //从核心中拿到任务
        scheduled = GetScheduledTask(core);
        if(scheduled != nullptr){
            if(scheduled->task_priority < hp_task->task_priority){
                return;
            }
            else if(scheduled->task_priority == hp_task->task_priority){
                if(scheduled->task_id == hp_task->task_id)
                    goto dequeue;
                else
                    return;
            }
            sched_EnqueueLocal(scheduled, core);

        }
dequeue:
        sched_SetLocalSchedTask(hp_task, core);
        sched_DequeueLocal(hp_task, core);
    }
}

void sched_Schedule(Core *core)
{
    sched_PrioTake(core);
}


void Enqueue_table_task(Task *task,Core *core)
{
    sched_EnqueueLocal(task, core);
    core->task_sched_type=task->task_type;
}




void Dequeue_table_task(Task *task,Core *core)
{
   Task *hp_task;
   ready_queue_node *head = core->ready_queue;
   if(head->next != head)
       if(head->next!=NULL)
        {
        hp_task = head->next->task;
        sched_SetLocalSchedTask(hp_task, core);
        sched_DequeueLocal(hp_task, core);
        core->task_sched_type=hp_task->task_type;
        }
}

/* ------------------------worst-fit------------------------------ */

int get_minU_core()
{
    double minU=100;
    int core_id=0;
    for(int i=0;i<get_corenum();i++)
    {
      //  qDebug()<<"核心"<<i<<"利用率"<<get_utilization(&cores[i]);
        if(get_utilization(&cores[i])<minU)
           {
            minU=get_utilization(&cores[i]);
            core_id=cores[i].core_id;
           }
    }
    return core_id;
}


double get_utilization(Core *core)
{
    return get_resource_utilization(core)+get_table_utilization(core)+get_rt_utilization(core);
}

double get_resource_utilization(Core *core)
{
    double total_utilization=0;
    int temp_wcet=0;
    for(int i=0;i<get_tasknum();i++)
        if(taskSets[i].task_type!=0)
        {
            for(int j=0;j<RESOURCE_MAX;j++)
                if((int)taskSets[i].resource_on_core[j]==core->core_id-1)
                    temp_wcet+=taskSets[i].resource_duration[j];
            total_utilization+=(double)temp_wcet/(double)taskSets[i].task_period;
        }
    return total_utilization;
}

double get_table_utilization(Core *core)
{
   int total_wcet=0;
   for(int i=0;i<get_tasknum();i++)
       if(taskSets[i].task_type==0)
           for(int j=0;j<taskSets[i].num_subsection;j++)
               if((int)taskSets[i].partition.part_on_core[j]==core->core_id-1)
                   total_wcet+=taskSets[i].partition.part_length[j];
   return (double)total_wcet/(double)lcm;
}

double get_rt_utilization(Core *core)
{
    double total_utilization=0;
    int temp_wcet=0;
    for(int i=0;i<get_tasknum();i++)
        if(taskSets[i].task_type!=0&&taskSets[i].on_core==core->core_id-1)
        {
            temp_wcet+=taskSets[i].task_wcet;
            for(int j=0;j<RESOURCE_MAX;j++)
                if(taskSets[i].resource_on_core[j]!=core->core_id-1)
                    temp_wcet-=taskSets[i].resource_duration[j];
            total_utilization+=(double)temp_wcet/(double)taskSets[i].task_period;
        }
    return total_utilization;
}
